import { defaultRequestConfig, RequestConfig, ResultModel } from './RequestApiModel'
import axios, { Method, AxiosResponse } from 'axios'
import { LocalStorageCache } from '@/utils/cache-util'
import { message } from 'ant-design-vue'
import { userStore } from '@/store'
// 全局请求拦截器
axios.interceptors.request.use(
  function (config) {
    // 在发送请求之前做些什么
    return config
  },
  function (error) {
    // 对请求错误做些什么
    message.error('服务器请求失败，请稍后重试...')
    return Promise.reject(error)
  },
)

// 全局响应拦截器
axios.interceptors.response.use(
  function (response) {
    // 对响应数据做点什么
    return response
  },
  function (error) {
    // 对响应错误做点什么
    message.error('服务器响应失败，请稍后重试...')
    return Promise.reject(error)
  },
)
/****
 * 请求工具类
 * todo 请求配置、响应拦截、数据转换、不同请求适配、缓存
 */
// 请求接口
interface Request<DATA> {
  // 获取数据
  get: () => Promise<DATA>
}
// 抽象请求类
abstract class AbstractRequest<CONFIG = any, DATA = any, P = any> implements Request<DATA> {
  // 请求配置
  config: CONFIG
  // 请求地址
  url: string
  // 请求方法
  method: Method
  // 参数
  params: P | undefined
  constructor(url: string, method: Method, params?: P, config: CONFIG = {} as CONFIG) {
    this.url = url
    this.method = method
    this.params = params
    this.config = config
  }
  // 默认get的实现方法
  get() {
    return Promise.resolve(undefined as unknown as DATA)
  }
}
// 请求处理父类
class RequestApi<T = any, P = any> extends AbstractRequest<RequestConfig, ResultModel<T>, P> {
  constructor(url: string, method: Method, params?: P, config?: RequestConfig<P>) {
    super(url, method, params, { ...defaultRequestConfig, ...config })
  }
  // 获取数据之前
  private async beforeGet(): Promise<ResultModel<T> | undefined> {
    const config = this.config
    // 如果需要开启缓存，但是没设置缓存键名，我们就手动添加
    if (config.cache && this.config.key) {
      const data = await new LocalStorageCache<ResultModel<T>>(this.config.key).get()
      if (data) {
        return Promise.resolve(data)
      } else {
        return Promise.resolve(undefined)
      }
    } else {
      return Promise.resolve(undefined)
    }
  }
  /**
   * 请求数据
   */
  async get(): Promise<ResultModel<T>> {
    await this.initConfig()
    // 如果缓存存在，则直接返回
    const data = await this.beforeGet()
    if (data) {
      console.info(`请求缓存${this.config.key}被使用`)
      return Promise.resolve(data)
    }
    return await this.afterGet(axios(this.config))
  }
  // 初始化配置
  private initConfig() {
    this.config.url = this.url
    this.config.method = this.method
    // @ts-ignore
    this.config.headers = {
      token: userStore().getToken,
      ...this.config.headers,
    }
    // query参数
    if (['get', 'GET', 'DELETE', 'delete'].includes(this.method)) {
      this.config.params = this.params
    }
    // body参数
    if (['post', 'POST', 'PUT', 'put'].includes(this.method)) {
      this.config.data = this.params
    }
  }
  // 响应拦截
  private async interceptors(result: Promise<AxiosResponse<ResultModel<T>, P>>): Promise<ResultModel<T>> {
    const { data } = await result
    // 响应结果拦截
    const { code, msg } = data
    if (code && code !== 200) {
      message.error(msg || '业务异常')
    }
    return data
  }
  // 请求数据之后
  private async afterGet(data: Promise<AxiosResponse<ResultModel<T>, P>>): Promise<ResultModel<T>> {
    const res = await this.interceptors(data)
    // 添加缓存
    if (this.config.cache && this.config.key) {
      console.info(`请求缓存${this.config.key}被设置`)
      new LocalStorageCache<ResultModel<T>>(this.config.key, this.config.limit).set(res)
    }
    return Promise.resolve(res)
  }
}
// post请求
class PostRequestApi<T, P = any> extends RequestApi<T> {
  constructor(url: string, params?: P, config?: RequestConfig) {
    super(url, 'post', params, config)
  }
}
// get请求
class GetRequestApi<T, P = any> extends RequestApi<T> {
  constructor(url: string, params?: P, config?: RequestConfig) {
    super(url, 'get', params, config)
  }
}
// put请求
class PutRequestApi<T, P = any> extends RequestApi<T> {
  constructor(url: string, params?: P, config?: RequestConfig) {
    super(url, 'put', params, config)
  }
}
// delete请求
class DeleteRequestApi<T, P = any> extends RequestApi<T> {
  constructor(url: string, params?: P, config?: RequestConfig) {
    super(url, 'delete', params, config)
  }
}
export { RequestApi, PostRequestApi, GetRequestApi, PutRequestApi, DeleteRequestApi }
